// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/compositor/layer_animator.h"

#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "cc/animation/animation_events.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_delegate.h"
#include "ui/compositor/layer_animation_element.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/layer_animator_collection.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/compositor/test/context_factories_for_test.h"
#include "ui/compositor/test/layer_animator_test_controller.h"
#include "ui/compositor/test/test_compositor_host.h"
#include "ui/compositor/test/test_layer_animation_delegate.h"
#include "ui/compositor/test/test_layer_animation_observer.h"
#include "ui/compositor/test/test_utils.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/transform.h"

namespace ui {

namespace {

    // Converts |color| to a string. Each component of the color is separated by a
    // space and the order if A R G B.
    std::string ColorToString(SkColor color)
    {
        return base::StringPrintf("%d %d %d %d", SkColorGetA(color),
            SkColorGetR(color), SkColorGetG(color),
            SkColorGetB(color));
    }

    // Creates vector with two LayerAnimationSequences, based on |first| and
    // |second| layer animation elements.
    std::vector<LayerAnimationSequence*> CreateMultiSequence(
        LayerAnimationElement* first,
        LayerAnimationElement* second)
    {
        LayerAnimationSequence* first_sequence = new LayerAnimationSequence();
        first_sequence->AddElement(first);
        LayerAnimationSequence* second_sequence = new LayerAnimationSequence();
        second_sequence->AddElement(second);

        std::vector<ui::LayerAnimationSequence*> animations;
        animations.push_back(first_sequence);
        animations.push_back(second_sequence);
        return animations;
    }

    // Creates a default animator with timers disabled for test. |delegate| and
    // |observer| are attached if non-null.
    LayerAnimator* CreateDefaultTestAnimator(LayerAnimationDelegate* delegate,
        LayerAnimationObserver* observer)
    {
        LayerAnimator* animator(LayerAnimator::CreateDefaultAnimator());
        animator->set_disable_timer_for_test(true);
        if (delegate)
            animator->SetDelegate(delegate);
        if (observer)
            animator->AddObserver(observer);
        return animator;
    }

    // Creates a default animator with timers disabled for test. |delegate| is
    // attached if non-null.
    LayerAnimator* CreateDefaultTestAnimator(LayerAnimationDelegate* delegate)
    {
        return CreateDefaultTestAnimator(delegate, nullptr);
    }

    // Creates a default animator with timers disabled for test.
    LayerAnimator* CreateDefaultTestAnimator()
    {
        return CreateDefaultTestAnimator(nullptr, nullptr);
    }

    // Creates an implicit animator with timers disabled for test. |delegate| and
    // |observer| are attached if non-null.
    LayerAnimator* CreateImplicitTestAnimator(LayerAnimationDelegate* delegate,
        LayerAnimationObserver* observer)
    {
        LayerAnimator* animator(LayerAnimator::CreateImplicitAnimator());
        animator->set_disable_timer_for_test(true);
        if (delegate)
            animator->SetDelegate(delegate);
        if (observer)
            animator->AddObserver(observer);
        return animator;
    }

    // Creates an implicit animator with timers disabled for test. |delegate| is
    // attached if non-null.
    LayerAnimator* CreateImplicitTestAnimator(LayerAnimationDelegate* delegate)
    {
        return CreateImplicitTestAnimator(delegate, nullptr);
    }

    // Creates an implicit animator with timers disabled for test.
    LayerAnimator* CreateImplicitTestAnimator()
    {
        return CreateImplicitTestAnimator(nullptr, nullptr);
    }

    class TestImplicitAnimationObserver : public ImplicitAnimationObserver {
    public:
        explicit TestImplicitAnimationObserver(bool notify_when_animator_destructed)
            : animations_completed_(false)
            , notify_when_animator_destructed_(notify_when_animator_destructed)
        {
        }

        bool animations_completed() const { return animations_completed_; }
        void set_animations_completed(bool completed)
        {
            animations_completed_ = completed;
        }

        bool WasAnimationAbortedForProperty(
            LayerAnimationElement::AnimatableProperty property) const
        {
            return ImplicitAnimationObserver::WasAnimationAbortedForProperty(property);
        }

        bool WasAnimationCompletedForProperty(
            LayerAnimationElement::AnimatableProperty property) const
        {
            return ImplicitAnimationObserver::WasAnimationCompletedForProperty(
                property);
        }

    private:
        // ImplicitAnimationObserver implementation
        void OnImplicitAnimationsCompleted() override
        {
            animations_completed_ = true;
        }

        bool RequiresNotificationWhenAnimatorDestroyed() const override
        {
            return notify_when_animator_destructed_;
        }

        bool animations_completed_;
        bool notify_when_animator_destructed_;

        DISALLOW_COPY_AND_ASSIGN(TestImplicitAnimationObserver);
    };

    // When notified that an animation has ended, stops all other animations.
    class DeletingLayerAnimationObserver : public LayerAnimationObserver {
    public:
        DeletingLayerAnimationObserver(LayerAnimator* animator)
            : animator_(animator)
        {
        }

        void OnLayerAnimationEnded(LayerAnimationSequence* sequence) override
        {
            animator_->StopAnimating();
        }

        void OnLayerAnimationAborted(LayerAnimationSequence* sequence) override
        {
            animator_->StopAnimating();
        }

        void OnLayerAnimationScheduled(LayerAnimationSequence* sequence) override { }

    private:
        LayerAnimator* animator_;

        DISALLOW_COPY_AND_ASSIGN(DeletingLayerAnimationObserver);
    };

    class LayerAnimatorDestructionObserver {
    public:
        LayerAnimatorDestructionObserver()
            : animator_deleted_(false)
        {
        }
        virtual ~LayerAnimatorDestructionObserver() { }

        void NotifyAnimatorDeleted()
        {
            animator_deleted_ = true;
        }

        bool IsAnimatorDeleted()
        {
            return animator_deleted_;
        }

    private:
        bool animator_deleted_;

        DISALLOW_COPY_AND_ASSIGN(LayerAnimatorDestructionObserver);
    };

    class TestLayerAnimator : public LayerAnimator {
    public:
        TestLayerAnimator()
            : LayerAnimator(base::TimeDelta::FromSeconds(0))
            , destruction_observer_(NULL)
        {
        }

        void SetDestructionObserver(
            LayerAnimatorDestructionObserver* observer)
        {
            destruction_observer_ = observer;
        }

    protected:
        ~TestLayerAnimator() override
        {
            if (destruction_observer_) {
                destruction_observer_->NotifyAnimatorDeleted();
            }
        }

        void ProgressAnimation(LayerAnimationSequence* sequence,
            base::TimeTicks now) override
        {
            EXPECT_TRUE(HasAnimation(sequence));
            LayerAnimator::ProgressAnimation(sequence, now);
        }

    private:
        LayerAnimatorDestructionObserver* destruction_observer_;

        DISALLOW_COPY_AND_ASSIGN(TestLayerAnimator);
    };

    // The test layer animation sequence updates a live instances count when it is
    // created and destroyed.
    class TestLayerAnimationSequence : public LayerAnimationSequence {
    public:
        TestLayerAnimationSequence(LayerAnimationElement* element,
            int* num_live_instances)
            : LayerAnimationSequence(element)
            , num_live_instances_(num_live_instances)
        {
            (*num_live_instances_)++;
        }

        ~TestLayerAnimationSequence() override { (*num_live_instances_)--; }

    private:
        int* num_live_instances_;

        DISALLOW_COPY_AND_ASSIGN(TestLayerAnimationSequence);
    };

} // namespace

// Checks that setting a property on an implicit animator causes an animation to
// happen.
TEST(LayerAnimatorTest, ImplicitAnimation)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateImplicitTestAnimator(&delegate));
    base::TimeTicks now = base::TimeTicks::Now();
    animator->SetBrightness(0.5);
    EXPECT_TRUE(animator->is_animating());
    animator->Step(now + base::TimeDelta::FromSeconds(1));
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), 0.5);
}

// Checks that if the animator is a default animator, that implicit animations
// are not started.
TEST(LayerAnimatorTest, NoImplicitAnimation)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));
    animator->SetBrightness(0.5);
    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), 0.5);
}

// Checks that StopAnimatingProperty stops animation for that property, and also
// skips the stopped animation to the end.
TEST(LayerAnimatorTest, StopAnimatingProperty)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateImplicitTestAnimator(&delegate));
    double target_opacity(0.5);
    gfx::Rect target_bounds(0, 0, 50, 50);
    animator->SetOpacity(target_opacity);
    animator->SetBounds(target_bounds);
    animator->StopAnimatingProperty(LayerAnimationElement::OPACITY);
    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), 0.5);
    animator->StopAnimatingProperty(LayerAnimationElement::BOUNDS);
    EXPECT_FALSE(animator->is_animating());
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), target_bounds);
}

// Checks that multiple running animations for separate properties can be
// stopped simultaneously and that all animations are advanced to their target
// values.
TEST(LayerAnimatorTest, StopAnimating)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateImplicitTestAnimator(&delegate));
    double target_opacity(0.5);
    gfx::Rect target_bounds(0, 0, 50, 50);
    animator->SetOpacity(target_opacity);
    animator->SetBounds(target_bounds);
    EXPECT_TRUE(animator->is_animating());
    animator->StopAnimating();
    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), 0.5);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), target_bounds);
}

// Checks that multiple running animations for separate properties can be
// stopped simultaneously and that aborted animations are NOT advanced to their
// target values.
TEST(LayerAnimatorTest, AbortAllAnimations)
{
    TestLayerAnimationDelegate delegate;
    double initial_opacity(1.0);
    gfx::Rect initial_bounds(0, 0, 10, 10);
    delegate.SetOpacityFromAnimation(initial_opacity);
    delegate.SetBoundsFromAnimation(initial_bounds);
    scoped_refptr<LayerAnimator> animator(CreateImplicitTestAnimator(&delegate));
    double target_opacity(0.5);
    gfx::Rect target_bounds(0, 0, 50, 50);
    animator->SetOpacity(target_opacity);
    animator->SetBounds(target_bounds);
    EXPECT_TRUE(animator->is_animating());
    animator->AbortAllAnimations();
    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(initial_opacity, delegate.GetOpacityForAnimation());
    CheckApproximatelyEqual(initial_bounds, delegate.GetBoundsForAnimation());
}

// Schedule a non-threaded animation that can run immediately. This is the
// trivial case and should result in the animation being started immediately.
TEST(LayerAnimatorTest, ScheduleAnimationThatCanRunImmediately)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_brightness(0.0);
    double middle_brightness(0.5);
    double target_brightness(1.0);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetBrightnessFromAnimation(start_brightness);

    animator->ScheduleAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
}

// Schedule a threaded animation that can run immediately.
TEST(LayerAnimatorTest, ScheduleThreadedAnimationThatCanRunImmediately)
{
    double epsilon = 0.00001;
    TestLayerAnimationDelegate delegate;
    LayerAnimatorTestController test_controller(
        CreateDefaultTestAnimator(&delegate));
    LayerAnimator* animator = test_controller.animator();

    double start_opacity(0.0);
    double target_opacity(1.0);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetOpacityFromAnimation(start_opacity);

    test_controller.animator()->ScheduleAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));

    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);

    base::TimeTicks start_time = test_controller.animator()->last_step_time();
    base::TimeTicks effective_start = start_time + delta;

    test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
        cc::AnimationEvent::STARTED, 0,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
            ->animation_group_id(),
        cc::Animation::OPACITY, effective_start));

    animator->Step(effective_start + delta / 2);

    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_NEAR(
        0.5,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->last_progressed_fraction(),
        epsilon);

    animator->Step(effective_start + delta);

    EXPECT_FALSE(test_controller.animator()->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
}

// Schedule two non-threaded animations on separate properties. Both animations
// should start immediately and should progress in lock step.
TEST(LayerAnimatorTest, ScheduleTwoAnimationsThatCanRunImmediately)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_brightness(0.0);
    double middle_brightness(0.5);
    double target_brightness(1.0);

    gfx::Rect start_bounds, target_bounds, middle_bounds;
    start_bounds = target_bounds = middle_bounds = gfx::Rect(0, 0, 50, 50);
    start_bounds.set_x(-90);
    target_bounds.set_x(90);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetBrightnessFromAnimation(start_brightness);
    delegate.SetBoundsFromAnimation(start_bounds);

    animator->ScheduleAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    animator->ScheduleAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBoundsElement(target_bounds, delta)));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), middle_bounds);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), target_bounds);
}

// Schedule a threaded and a non-threaded animation on separate properties. Both
// animations should progress in lock step.
TEST(LayerAnimatorTest, ScheduleThreadedAndNonThreadedAnimations)
{
    double epsilon = 0.00001;
    TestLayerAnimationDelegate delegate;
    LayerAnimatorTestController test_controller(
        CreateDefaultTestAnimator(&delegate));
    LayerAnimator* animator = test_controller.animator();

    double start_opacity(0.0);
    double target_opacity(1.0);

    gfx::Rect start_bounds, target_bounds, middle_bounds;
    start_bounds = target_bounds = middle_bounds = gfx::Rect(0, 0, 50, 50);
    start_bounds.set_x(-90);
    target_bounds.set_x(90);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetOpacityFromAnimation(start_opacity);
    delegate.SetBoundsFromAnimation(start_bounds);

    std::vector<LayerAnimationSequence*> animations;
    animations.push_back(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));

    animations.push_back(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBoundsElement(target_bounds, delta)));

    test_controller.animator()->ScheduleTogether(animations);

    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);

    base::TimeTicks start_time = test_controller.animator()->last_step_time();
    base::TimeTicks effective_start = start_time + delta;

    test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
        cc::AnimationEvent::STARTED, 0,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
            ->animation_group_id(),
        cc::Animation::OPACITY, effective_start));

    animator->Step(effective_start + delta / 2);

    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_NEAR(
        0.5,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->last_progressed_fraction(),
        epsilon);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), middle_bounds);

    animator->Step(effective_start + delta);

    EXPECT_FALSE(test_controller.animator()->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), target_bounds);
}

// Schedule two animations on the same property. In this case, the two
// animations should run one after another.
TEST(LayerAnimatorTest, ScheduleTwoAnimationsOnSameProperty)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_brightness(0.0);
    double middle_brightness(0.5);
    double target_brightness(1.0);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetBrightnessFromAnimation(start_brightness);

    animator->ScheduleAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    animator->ScheduleAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(start_brightness,
                delta)));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}

// Schedule [{g}, {g,b}, {b}] and ensure that {b} doesn't run right away. That
// is, ensure that all animations targetting a particular property are run in
// order.
TEST(LayerAnimatorTest, ScheduleBlockedAnimation)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_grayscale(0.0);
    double middle_grayscale(0.5);
    double target_grayscale(1.0);

    gfx::Rect start_bounds, target_bounds, middle_bounds;
    start_bounds = target_bounds = middle_bounds = gfx::Rect(0, 0, 50, 50);
    start_bounds.set_x(-90);
    target_bounds.set_x(90);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetGrayscaleFromAnimation(start_grayscale);
    delegate.SetBoundsFromAnimation(start_bounds);

    animator->ScheduleAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateGrayscaleElement(target_grayscale,
                delta)));

    scoped_ptr<LayerAnimationSequence> bounds_and_grayscale(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateGrayscaleElement(start_grayscale,
                delta)));

    bounds_and_grayscale->AddElement(
        LayerAnimationElement::CreateBoundsElement(target_bounds, delta));

    animator->ScheduleAnimation(bounds_and_grayscale.release());

    animator->ScheduleAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBoundsElement(start_bounds, delta)));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), target_grayscale);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(3000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), target_bounds);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(4000));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);
}

// Schedule {g} and then schedule {g} and {b} together. In this case, since
// ScheduleTogether is being used, the bounds animation should not start until
// the second grayscale animation starts.
TEST(LayerAnimatorTest, ScheduleTogether)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_grayscale(0.0);
    double target_grayscale(1.0);

    gfx::Rect start_bounds, target_bounds, middle_bounds;
    start_bounds = target_bounds = gfx::Rect(0, 0, 50, 50);
    start_bounds.set_x(-90);
    target_bounds.set_x(90);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetGrayscaleFromAnimation(start_grayscale);
    delegate.SetBoundsFromAnimation(start_bounds);

    animator->ScheduleAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateGrayscaleElement(target_grayscale,
                delta)));

    std::vector<LayerAnimationSequence*> sequences;
    sequences.push_back(new LayerAnimationSequence(
        LayerAnimationElement::CreateGrayscaleElement(start_grayscale, delta)));
    sequences.push_back(new LayerAnimationSequence(
        LayerAnimationElement::CreateBoundsElement(target_bounds, delta)));

    animator->ScheduleTogether(sequences);

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), target_grayscale);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), start_bounds);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), target_bounds);
}

// Start non-threaded animation (that can run immediately). This is the trivial
// case (see the trival case for ScheduleAnimation).
TEST(LayerAnimatorTest, StartAnimationThatCanRunImmediately)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_brightness(0.0);
    double middle_brightness(0.5);
    double target_brightness(1.0);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetBrightnessFromAnimation(start_brightness);

    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
}

// Start threaded animation (that can run immediately).
TEST(LayerAnimatorTest, StartThreadedAnimationThatCanRunImmediately)
{
    double epsilon = 0.00001;
    TestLayerAnimationDelegate delegate;
    LayerAnimatorTestController test_controller(
        CreateDefaultTestAnimator(&delegate));
    LayerAnimator* animator = test_controller.animator();

    double start_opacity(0.0);
    double target_opacity(1.0);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetOpacityFromAnimation(start_opacity);

    test_controller.animator()->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));

    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);

    base::TimeTicks start_time = test_controller.animator()->last_step_time();
    base::TimeTicks effective_start = start_time + delta;

    test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
        cc::AnimationEvent::STARTED, 0,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
            ->animation_group_id(),
        cc::Animation::OPACITY, effective_start));

    animator->Step(effective_start + delta / 2);

    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_NEAR(
        0.5,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->last_progressed_fraction(),
        epsilon);

    animator->Step(effective_start + delta);
    EXPECT_FALSE(test_controller.animator()->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
}

// Preempt by immediately setting new target.
TEST(LayerAnimatorTest, PreemptBySettingNewTarget)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_opacity(0.0);
    double target_opacity(1.0);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetOpacityFromAnimation(start_opacity);

    animator->set_preemption_strategy(LayerAnimator::IMMEDIATELY_SET_NEW_TARGET);

    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));

    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateOpacityElement(start_opacity, delta)));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
}

// Preempt by animating to new target, with a non-threaded animation.
TEST(LayerAnimatorTest, PreemptByImmediatelyAnimatingToNewTarget)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_brightness(0.0);
    double middle_brightness(0.5);
    double target_brightness(1.0);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetBrightnessFromAnimation(start_brightness);

    animator->set_preemption_strategy(
        LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);

    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));

    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(start_brightness,
                delta)));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(start_brightness,
                delta)));

    EXPECT_TRUE(animator->is_animating());

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(),
        0.5 * (start_brightness + middle_brightness));

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}

// Preempt by animating to new target, with a threaded animation.
TEST(LayerAnimatorTest, PreemptThreadedByImmediatelyAnimatingToNewTarget)
{
    double epsilon = 0.00001;
    TestLayerAnimationDelegate delegate;
    LayerAnimatorTestController test_controller(
        CreateDefaultTestAnimator(&delegate));
    LayerAnimator* animator = test_controller.animator();

    double start_opacity(0.0);
    double middle_opacity(0.5);
    double target_opacity(1.0);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetOpacityFromAnimation(start_opacity);

    test_controller.animator()->set_preemption_strategy(
        LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);

    test_controller.animator()->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));

    base::TimeTicks start_time = test_controller.animator()->last_step_time();
    base::TimeTicks effective_start = start_time + delta;

    test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
        cc::AnimationEvent::STARTED, 0,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
            ->animation_group_id(),
        cc::Animation::OPACITY, effective_start));

    animator->Step(effective_start + delta / 2);

    test_controller.animator()->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateOpacityElement(start_opacity, delta)));

    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_NEAR(delegate.GetOpacityForAnimation(), middle_opacity, epsilon);

    test_controller.animator()->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateOpacityElement(start_opacity, delta)));

    EXPECT_TRUE(test_controller.animator()->is_animating());

    base::TimeTicks second_effective_start = effective_start + delta;

    test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
        cc::AnimationEvent::STARTED, 0,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
            ->animation_group_id(),
        cc::Animation::OPACITY, second_effective_start));

    animator->Step(second_effective_start + delta / 2);

    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_NEAR(
        0.5,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->last_progressed_fraction(),
        epsilon);

    animator->Step(second_effective_start + delta);

    EXPECT_FALSE(test_controller.animator()->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
}

// Preempt by enqueuing the new animation.
TEST(LayerAnimatorTest, PreemptEnqueueNewAnimation)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_brightness(0.0);
    double middle_brightness(0.5);
    double target_brightness(1.0);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetBrightnessFromAnimation(start_brightness);

    animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);

    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));

    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(start_brightness,
                delta)));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    EXPECT_TRUE(animator->is_animating());

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}

// Start an animation when there are sequences waiting in the queue. In this
// case, all pending and running animations should be finished, and the new
// animation started.
TEST(LayerAnimatorTest, PreemptyByReplacingQueuedAnimations)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_brightness(0.0);
    double middle_brightness(0.5);
    double target_brightness(1.0);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetBrightnessFromAnimation(start_brightness);

    animator->set_preemption_strategy(LayerAnimator::REPLACE_QUEUED_ANIMATIONS);

    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));

    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(middle_brightness,
                delta)));

    // Queue should now have two animations. Starting a third should replace the
    // second.
    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(start_brightness,
                delta)));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}

TEST(LayerAnimatorTest, StartTogetherSetsLastStepTime)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_grayscale(0.0);
    double target_grayscale(1.0);
    double start_brightness(0.1);
    double target_brightness(0.9);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetGrayscaleFromAnimation(start_grayscale);
    delegate.SetBrightnessFromAnimation(start_brightness);

    animator->set_preemption_strategy(
        LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);

    animator->set_last_step_time(base::TimeTicks());

    animator->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateGrayscaleElement(target_grayscale,
                delta),
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    // If last step time was not set correctly, the resulting delta should be
    // miniscule (fractions of a millisecond). If set correctly, then the delta
    // should be enormous. Arbitrarily choosing 1 minute as the threshold,
    // though a much smaller value would probably have sufficed.
    delta = base::TimeTicks::Now() - animator->last_step_time();
    EXPECT_GT(60.0, delta.InSecondsF());
}

//-------------------------------------------------------
// Preempt by immediately setting new target.
TEST(LayerAnimatorTest, MultiPreemptBySettingNewTarget)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_opacity(0.0);
    double target_opacity(1.0);
    double start_brightness(0.1);
    double target_brightness(0.9);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetOpacityFromAnimation(start_opacity);
    delegate.SetBrightnessFromAnimation(start_brightness);

    animator->set_preemption_strategy(LayerAnimator::IMMEDIATELY_SET_NEW_TARGET);

    animator->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateOpacityElement(target_opacity, delta),
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    animator->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
            LayerAnimationElement::CreateBrightnessElement(start_brightness,
                delta)));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}

// Preempt by animating to new target.
TEST(LayerAnimatorTest, MultiPreemptByImmediatelyAnimatingToNewTarget)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_grayscale(0.0);
    double middle_grayscale(0.5);
    double target_grayscale(1.0);

    double start_brightness(0.1);
    double middle_brightness(0.2);
    double target_brightness(0.3);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetGrayscaleFromAnimation(start_grayscale);
    delegate.SetBrightnessFromAnimation(start_brightness);

    animator->set_preemption_strategy(
        LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);

    animator->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateGrayscaleElement(target_grayscale,
                delta),
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));

    animator->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateGrayscaleElement(start_grayscale, delta),
            LayerAnimationElement::CreateBrightnessElement(start_brightness,
                delta)));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    animator->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateGrayscaleElement(start_grayscale, delta),
            LayerAnimationElement::CreateBrightnessElement(start_brightness,
                delta)));

    EXPECT_TRUE(animator->is_animating());

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(),
        0.5 * (start_grayscale + middle_grayscale));
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(),
        0.5 * (start_brightness + middle_brightness));

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}

// Preempt a threaded animation by animating to new target.
TEST(LayerAnimatorTest, MultiPreemptThreadedByImmediatelyAnimatingToNewTarget)
{
    double epsilon = 0.00001;
    TestLayerAnimationDelegate delegate;
    LayerAnimatorTestController test_controller(
        CreateDefaultTestAnimator(&delegate));
    LayerAnimator* animator = test_controller.animator();

    double start_opacity(0.0);
    double middle_opacity(0.5);
    double target_opacity(1.0);

    double start_brightness(0.1);
    double middle_brightness(0.2);
    double target_brightness(0.3);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetOpacityFromAnimation(start_opacity);
    delegate.SetBrightnessFromAnimation(start_brightness);

    test_controller.animator()->set_preemption_strategy(
        LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);

    test_controller.animator()->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateOpacityElement(target_opacity, delta),
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    base::TimeTicks start_time = test_controller.animator()->last_step_time();
    base::TimeTicks effective_start = start_time + delta;

    test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
        cc::AnimationEvent::STARTED, 0,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
            ->animation_group_id(),
        cc::Animation::OPACITY, effective_start));

    animator->Step(effective_start + delta / 2);

    test_controller.animator()->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
            LayerAnimationElement::CreateBrightnessElement(start_brightness,
                delta)));

    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_NEAR(delegate.GetOpacityForAnimation(), middle_opacity, epsilon);
    EXPECT_NEAR(delegate.GetBrightnessForAnimation(), middle_brightness, epsilon);

    test_controller.animator()->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
            LayerAnimationElement::CreateBrightnessElement(start_brightness,
                delta)));

    EXPECT_TRUE(test_controller.animator()->is_animating());

    base::TimeTicks second_effective_start = effective_start + delta;

    test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
        cc::AnimationEvent::STARTED, 0,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
            ->animation_group_id(),
        cc::Animation::OPACITY, second_effective_start));

    animator->Step(second_effective_start + delta / 2);

    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_NEAR(
        0.5,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)->last_progressed_fraction(),
        epsilon);
    EXPECT_NEAR(delegate.GetBrightnessForAnimation(),
        0.5 * (start_brightness + middle_brightness),
        epsilon);

    animator->Step(second_effective_start + delta);

    EXPECT_FALSE(test_controller.animator()->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}

// Preempt by enqueuing the new animation.
TEST(LayerAnimatorTest, MultiPreemptEnqueueNewAnimation)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_grayscale(0.0);
    double middle_grayscale(0.5);
    double target_grayscale(1.0);

    double start_brightness(0.1);
    double middle_brightness(0.2);
    double target_brightness(0.3);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetGrayscaleFromAnimation(start_grayscale);
    delegate.SetBrightnessFromAnimation(start_brightness);

    animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);

    animator->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateGrayscaleElement(target_grayscale,
                delta),
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));

    animator->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateGrayscaleElement(start_grayscale, delta),
            LayerAnimationElement::CreateBrightnessElement(start_brightness,
                delta)));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    EXPECT_TRUE(animator->is_animating());

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), target_grayscale);
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}

// Start an animation when there are sequences waiting in the queue. In this
// case, all pending and running animations should be finished, and the new
// animation started.
TEST(LayerAnimatorTest, MultiPreemptByReplacingQueuedAnimations)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_grayscale(0.0);
    double middle_grayscale(0.5);
    double target_grayscale(1.0);

    double start_brightness(0.1);
    double middle_brightness(0.2);
    double target_brightness(0.3);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetGrayscaleFromAnimation(start_grayscale);
    delegate.SetBrightnessFromAnimation(start_brightness);

    animator->set_preemption_strategy(LayerAnimator::REPLACE_QUEUED_ANIMATIONS);

    animator->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateGrayscaleElement(target_grayscale,
                delta),
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));

    animator->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateGrayscaleElement(middle_grayscale,
                delta),
            LayerAnimationElement::CreateBrightnessElement(middle_brightness,
                delta)));

    // Queue should now have two animations. Starting a third should replace the
    // second.
    animator->StartTogether(
        CreateMultiSequence(
            LayerAnimationElement::CreateGrayscaleElement(start_grayscale, delta),
            LayerAnimationElement::CreateBrightnessElement(start_brightness,
                delta)));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), target_grayscale);
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), middle_grayscale);
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetGrayscaleForAnimation(), start_grayscale);
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
}
//-------------------------------------------------------
// Test that non-threaded cyclic sequences continue to animate.
TEST(LayerAnimatorTest, CyclicSequences)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_brightness(0.0);
    double target_brightness(1.0);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetBrightnessFromAnimation(start_brightness);

    scoped_ptr<LayerAnimationSequence> sequence(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(target_brightness,
                delta)));

    sequence->AddElement(
        LayerAnimationElement::CreateBrightnessElement(start_brightness, delta));

    sequence->set_is_cyclic(true);

    animator->StartAnimation(sequence.release());

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(2000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(3000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);

    // Skip ahead by a lot.
    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000000000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);

    // Skip ahead by a lot.
    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000001000));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);

    animator->StopAnimatingProperty(LayerAnimationElement::BRIGHTNESS);

    EXPECT_FALSE(animator->is_animating());
}

// Test that threaded cyclic sequences continue to animate.
TEST(LayerAnimatorTest, ThreadedCyclicSequences)
{
    TestLayerAnimationDelegate delegate;
    LayerAnimatorTestController test_controller(
        CreateDefaultTestAnimator(&delegate));
    LayerAnimator* animator = test_controller.animator();

    double start_opacity(0.0);
    double target_opacity(1.0);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetOpacityFromAnimation(start_opacity);

    scoped_ptr<LayerAnimationSequence> sequence(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));

    sequence->AddElement(
        LayerAnimationElement::CreateOpacityElement(start_opacity, delta));

    sequence->set_is_cyclic(true);

    test_controller.animator()->StartAnimation(sequence.release());

    base::TimeTicks start_time = test_controller.animator()->last_step_time();
    base::TimeTicks effective_start = start_time + delta;

    test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
        cc::AnimationEvent::STARTED, 0,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
            ->animation_group_id(),
        cc::Animation::OPACITY, effective_start));

    animator->Step(effective_start + delta);
    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);

    base::TimeTicks second_effective_start = effective_start + 2 * delta;
    test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
        cc::AnimationEvent::STARTED, 0,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
            ->animation_group_id(),
        cc::Animation::OPACITY, second_effective_start));

    animator->Step(second_effective_start + delta);

    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);

    base::TimeTicks third_effective_start = second_effective_start + 2 * delta;
    test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
        cc::AnimationEvent::STARTED, 0,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
            ->animation_group_id(),
        cc::Animation::OPACITY, third_effective_start));

    animator->Step(third_effective_start + delta);
    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);

    base::TimeTicks fourth_effective_start = third_effective_start + 2 * delta;
    test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
        cc::AnimationEvent::STARTED, 0,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
            ->animation_group_id(),
        cc::Animation::OPACITY, fourth_effective_start));

    // Skip ahead by a lot.
    animator->Step(fourth_effective_start + 1000 * delta);

    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);

    base::TimeTicks fifth_effective_start = fourth_effective_start + 1001 * delta;
    test_controller.animator()->OnThreadedAnimationStarted(cc::AnimationEvent(
        cc::AnimationEvent::STARTED, 0,
        test_controller.GetRunningSequence(LayerAnimationElement::OPACITY)
            ->animation_group_id(),
        cc::Animation::OPACITY, fifth_effective_start));

    // Skip ahead by a lot.
    animator->Step(fifth_effective_start + 999 * delta);

    EXPECT_TRUE(test_controller.animator()->is_animating());
    EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);

    test_controller.animator()->StopAnimatingProperty(
        LayerAnimationElement::OPACITY);

    EXPECT_FALSE(test_controller.animator()->is_animating());
}

TEST(LayerAnimatorTest, AddObserverExplicit)
{
    TestLayerAnimationObserver observer;
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(
        CreateDefaultTestAnimator(&delegate, &observer));
    observer.set_requires_notification_when_animator_destroyed(true);

    EXPECT_TRUE(!observer.last_ended_sequence());

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetBrightnessFromAnimation(0.0f);

    LayerAnimationSequence* sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateBrightnessElement(1.0f, delta));

    animator->StartAnimation(sequence);

    EXPECT_EQ(observer.last_scheduled_sequence(), sequence);

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_EQ(observer.last_ended_sequence(), sequence);

    // |sequence| has been destroyed. Recreate it to test abort.
    sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateBrightnessElement(1.0f, delta));

    animator->StartAnimation(sequence);

    animator = NULL;

    EXPECT_EQ(observer.last_aborted_sequence(), sequence);
}

// Tests that an observer added to a scoped settings object is still notified
// when the object goes out of scope.
TEST(LayerAnimatorTest, ImplicitAnimationObservers)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));
    TestImplicitAnimationObserver observer(false);

    EXPECT_FALSE(observer.animations_completed());
    animator->SetBrightness(1.0f);

    {
        ScopedLayerAnimationSettings settings(animator.get());
        settings.AddObserver(&observer);
        animator->SetBrightness(0.0f);
    }

    EXPECT_FALSE(observer.animations_completed());
    base::TimeTicks start_time = animator->last_step_time();
    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
    EXPECT_TRUE(observer.animations_completed());
    EXPECT_TRUE(observer.WasAnimationCompletedForProperty(
        LayerAnimationElement::BRIGHTNESS));
    EXPECT_FLOAT_EQ(0.0f, delegate.GetBrightnessForAnimation());
}

// Tests that an observer added to a scoped settings object is still notified
// when the object goes out of scope due to the animation being interrupted.
TEST(LayerAnimatorTest, InterruptedImplicitAnimationObservers)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));
    TestImplicitAnimationObserver observer(false);

    EXPECT_FALSE(observer.animations_completed());
    animator->SetBrightness(1.0f);

    {
        ScopedLayerAnimationSettings settings(animator.get());
        settings.AddObserver(&observer);
        animator->SetBrightness(0.0f);
    }

    EXPECT_FALSE(observer.animations_completed());
    // This should interrupt the implicit animation causing the observer to be
    // notified immediately.
    animator->SetBrightness(1.0f);
    EXPECT_TRUE(observer.animations_completed());
    EXPECT_TRUE(observer.WasAnimationCompletedForProperty(
        LayerAnimationElement::BRIGHTNESS));
    EXPECT_FLOAT_EQ(1.0f, delegate.GetBrightnessForAnimation());
}

// Tests that LayerAnimator is not deleted after the animation completes as long
// as there is a live ScopedLayerAnimationSettings object wrapped around it.
TEST(LayerAnimatorTest, AnimatorKeptAliveBySettings)
{
    // Note we are using a raw pointer unlike in other tests.
    TestLayerAnimator* animator = new TestLayerAnimator();
    LayerAnimatorDestructionObserver destruction_observer;
    animator->SetDestructionObserver(&destruction_observer);
    animator->set_disable_timer_for_test(true);
    TestLayerAnimationDelegate delegate;
    animator->SetDelegate(&delegate);
    {
        // ScopedLayerAnimationSettings should keep the Animator alive as long as
        // it is alive, even beyond the end of the animation.
        ScopedLayerAnimationSettings settings(animator);
        base::TimeTicks now = base::TimeTicks::Now();
        animator->SetBrightness(0.5);
        animator->Step(now + base::TimeDelta::FromSeconds(1));
        EXPECT_FALSE(destruction_observer.IsAnimatorDeleted());
    }
    // ScopedLayerAnimationSettings was destroyed, so Animator should be deleted.
    EXPECT_TRUE(destruction_observer.IsAnimatorDeleted());
}

// Tests that an observer added to a scoped settings object is not notified
// when the animator is destroyed unless explicitly requested.
TEST(LayerAnimatorTest, ImplicitObserversAtAnimatorDestruction)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));
    TestImplicitAnimationObserver observer_notify(true);
    TestImplicitAnimationObserver observer_do_not_notify(false);

    EXPECT_FALSE(observer_notify.animations_completed());
    EXPECT_FALSE(observer_do_not_notify.animations_completed());

    animator->SetBrightness(1.0f);

    {
        ScopedLayerAnimationSettings settings(animator.get());
        settings.AddObserver(&observer_notify);
        settings.AddObserver(&observer_do_not_notify);
        animator->SetBrightness(0.0f);
    }

    EXPECT_FALSE(observer_notify.animations_completed());
    EXPECT_FALSE(observer_do_not_notify.animations_completed());
    animator = NULL;
    EXPECT_TRUE(observer_notify.animations_completed());
    EXPECT_TRUE(observer_notify.WasAnimationAbortedForProperty(
        LayerAnimationElement::BRIGHTNESS));
    EXPECT_FALSE(observer_do_not_notify.animations_completed());
}

TEST(LayerAnimatorTest, AbortedAnimationStatusInImplicitObservers)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));
    TestImplicitAnimationObserver observer(false);

    EXPECT_FALSE(observer.animations_completed());
    animator->SetBrightness(1.0f);

    {
        ScopedLayerAnimationSettings settings(animator.get());
        settings.AddObserver(&observer);
        animator->SetBrightness(0.0f);
    }
    EXPECT_FALSE(observer.animations_completed());

    animator->AbortAllAnimations();
    EXPECT_TRUE(observer.animations_completed());
    EXPECT_TRUE(observer.WasAnimationAbortedForProperty(
        LayerAnimationElement::BRIGHTNESS));
    EXPECT_FALSE(observer.WasAnimationAbortedForProperty(
        LayerAnimationElement::OPACITY));

    observer.set_animations_completed(false);
    {
        ScopedLayerAnimationSettings settings(animator.get());
        settings.AddObserver(&observer);
        animator->SetOpacity(0.0f);
    }
    EXPECT_FALSE(observer.animations_completed());

    animator->AbortAllAnimations();
    EXPECT_TRUE(observer.animations_completed());
    EXPECT_TRUE(observer.WasAnimationAbortedForProperty(
        LayerAnimationElement::BRIGHTNESS));
    EXPECT_TRUE(observer.WasAnimationAbortedForProperty(
        LayerAnimationElement::OPACITY));
}

TEST(LayerAnimatorTest, RemoveObserverShouldRemoveFromSequences)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));
    TestLayerAnimationObserver observer;
    TestLayerAnimationObserver removed_observer;

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    LayerAnimationSequence* sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateBrightnessElement(1.0f, delta));

    sequence->AddObserver(&observer);
    sequence->AddObserver(&removed_observer);

    animator->StartAnimation(sequence);

    EXPECT_EQ(observer.last_scheduled_sequence(), sequence);
    EXPECT_TRUE(!observer.last_ended_sequence());
    EXPECT_EQ(removed_observer.last_scheduled_sequence(), sequence);
    EXPECT_TRUE(!removed_observer.last_ended_sequence());

    // This should stop the observer from observing sequence.
    animator->RemoveObserver(&removed_observer);

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_EQ(observer.last_ended_sequence(), sequence);
    EXPECT_TRUE(!removed_observer.last_ended_sequence());
}

TEST(LayerAnimatorTest, ObserverReleasedBeforeAnimationSequenceEnds)
{
    TestLayerAnimationDelegate delegate;
    scoped_ptr<TestLayerAnimationObserver> observer(
        new TestLayerAnimationObserver);
    scoped_refptr<LayerAnimator> animator(
        CreateDefaultTestAnimator(&delegate, observer.get()));

    delegate.SetOpacityFromAnimation(0.0f);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
    LayerAnimationSequence* sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateOpacityElement(1.0f, delta));

    animator->StartAnimation(sequence);

    // |observer| should be attached to |sequence|.
    EXPECT_TRUE(sequence->observers_.might_have_observers());

    // Now, release |observer|
    observer.reset();

    // And |sequence| should no longer be attached to |observer|.
    EXPECT_FALSE(sequence->observers_.might_have_observers());
}

TEST(LayerAnimatorTest, ObserverAttachedAfterAnimationStarted)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    TestImplicitAnimationObserver observer(false);

    delegate.SetBrightnessFromAnimation(0.0f);

    {
        ScopedLayerAnimationSettings setter(animator.get());

        base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
        LayerAnimationSequence* sequence = new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(1.0f, delta));

        animator->StartAnimation(sequence);
        base::TimeTicks start_time = animator->last_step_time();
        animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));

        setter.AddObserver(&observer);

        // Start observing an in-flight animation.
        sequence->AddObserver(&observer);

        animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
    }

    EXPECT_TRUE(observer.animations_completed());
    EXPECT_TRUE(observer.WasAnimationCompletedForProperty(
        LayerAnimationElement::BRIGHTNESS));
}

TEST(LayerAnimatorTest, ObserverDetachedBeforeAnimationFinished)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    TestImplicitAnimationObserver observer(false);

    delegate.SetBrightnessFromAnimation(0.0f);
    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
    LayerAnimationSequence* sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateBrightnessElement(1.0f, delta));

    {
        ScopedLayerAnimationSettings setter(animator.get());
        setter.AddObserver(&observer);

        animator->StartAnimation(sequence);
        base::TimeTicks start_time = animator->last_step_time();
        animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));
    }

    EXPECT_FALSE(observer.animations_completed());

    // Stop observing an in-flight animation.
    sequence->RemoveObserver(&observer);

    EXPECT_TRUE(observer.animations_completed());

    // The animation didn't complete, and neither was it aborted.
    EXPECT_FALSE(observer.WasAnimationCompletedForProperty(
        LayerAnimationElement::BRIGHTNESS));
    EXPECT_FALSE(observer.WasAnimationAbortedForProperty(
        LayerAnimationElement::BRIGHTNESS));
}

// This checks that if an animation is deleted due to a callback, that the
// animator does not try to use the deleted animation. For example, if we have
// two running animations, and the first finishes and the resulting callback
// causes the second to be deleted, we should not attempt to animate the second
// animation.
TEST(LayerAnimatorTest, ObserverDeletesAnimationsOnEnd)
{
    ScopedAnimationDurationScaleMode normal_duration_mode(
        ScopedAnimationDurationScaleMode::NORMAL_DURATION);
    scoped_refptr<LayerAnimator> animator(new TestLayerAnimator());
    animator->set_disable_timer_for_test(true);
    TestLayerAnimationDelegate delegate;
    animator->SetDelegate(&delegate);

    double start_brightness(0.0);
    double target_brightness(1.0);

    gfx::Rect start_bounds(0, 0, 50, 50);
    gfx::Rect target_bounds(5, 5, 5, 5);

    delegate.SetBrightnessFromAnimation(start_brightness);
    delegate.SetBoundsFromAnimation(start_bounds);

    base::TimeDelta brightness_delta = base::TimeDelta::FromSeconds(1);
    base::TimeDelta halfway_delta = base::TimeDelta::FromSeconds(2);
    base::TimeDelta bounds_delta = base::TimeDelta::FromSeconds(3);

    scoped_ptr<DeletingLayerAnimationObserver> observer(
        new DeletingLayerAnimationObserver(animator.get()));

    animator->AddObserver(observer.get());

    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(
                target_brightness, brightness_delta)));

    animator->StartAnimation(new LayerAnimationSequence(
        LayerAnimationElement::CreateBoundsElement(
            target_bounds, bounds_delta)));
    ASSERT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));

    base::TimeTicks start_time = animator->last_step_time();
    animator->Step(start_time + halfway_delta);

    // Completing the brightness animation should have stopped the bounds
    // animation.
    ASSERT_FALSE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));

    animator->RemoveObserver(observer.get());
}

// Ensure that stopping animation in a bounds change does not crash and that
// animation gets stopped correctly.
// This scenario is possible when animation is restarted from inside a
// callback triggered by the animation progress.
TEST(LayerAnimatorTest, CallbackDeletesAnimationInProgress)
{

    class TestLayerAnimationDeletingDelegate : public TestLayerAnimationDelegate {
    public:
        TestLayerAnimationDeletingDelegate(LayerAnimator* animator, int max_width)
            : animator_(animator)
            , max_width_(max_width)
        {
        }

        void SetBoundsFromAnimation(const gfx::Rect& bounds) override
        {
            TestLayerAnimationDelegate::SetBoundsFromAnimation(bounds);
            if (bounds.width() > max_width_)
                animator_->StopAnimating();
        }

    private:
        LayerAnimator* animator_;
        int max_width_;
        // Allow copy and assign.
    };

    ScopedAnimationDurationScaleMode normal_duration_mode(
        ScopedAnimationDurationScaleMode::NORMAL_DURATION);
    scoped_refptr<LayerAnimator> animator(new TestLayerAnimator());
    animator->set_disable_timer_for_test(true);
    TestLayerAnimationDeletingDelegate delegate(animator.get(), 30);
    animator->SetDelegate(&delegate);

    gfx::Rect start_bounds(0, 0, 0, 0);
    gfx::Rect target_bounds(5, 5, 50, 50);

    delegate.SetBoundsFromAnimation(start_bounds);

    base::TimeDelta bounds_delta1 = base::TimeDelta::FromMilliseconds(333);
    base::TimeDelta bounds_delta2 = base::TimeDelta::FromMilliseconds(666);
    base::TimeDelta bounds_delta = base::TimeDelta::FromMilliseconds(1000);
    base::TimeDelta final_delta = base::TimeDelta::FromMilliseconds(1500);

    animator->StartAnimation(new LayerAnimationSequence(
        LayerAnimationElement::CreateBoundsElement(
            target_bounds, bounds_delta)));
    ASSERT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));

    base::TimeTicks start_time = animator->last_step_time();
    ASSERT_NO_FATAL_FAILURE(animator->Step(start_time + bounds_delta1));
    ASSERT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));

    // The next step should change the animated bounds past the threshold and
    // cause the animaton to stop.
    ASSERT_NO_FATAL_FAILURE(animator->Step(start_time + bounds_delta2));
    ASSERT_FALSE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));
    ASSERT_NO_FATAL_FAILURE(animator->Step(start_time + final_delta));

    // Completing the animation should have stopped the bounds
    // animation.
    ASSERT_FALSE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));
}

// Similar to the ObserverDeletesAnimationsOnEnd test above except that it
// tests the behavior when the OnLayerAnimationAborted() callback causes
// all of the animator's other animations to be deleted.
TEST(LayerAnimatorTest, ObserverDeletesAnimationsOnAbort)
{
    ScopedAnimationDurationScaleMode test_duration_mode(
        ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
    scoped_refptr<LayerAnimator> animator(new TestLayerAnimator());
    animator->set_disable_timer_for_test(true);
    TestLayerAnimationDelegate delegate;
    animator->SetDelegate(&delegate);

    double start_brightness(0.0);
    double target_brightness(1.0);
    gfx::Rect start_bounds(0, 0, 50, 50);
    gfx::Rect target_bounds(5, 5, 5, 5);
    base::TimeDelta brightness_delta = base::TimeDelta::FromSeconds(1);
    base::TimeDelta bounds_delta = base::TimeDelta::FromSeconds(2);

    delegate.SetBrightnessFromAnimation(start_brightness);
    delegate.SetBoundsFromAnimation(start_bounds);

    scoped_ptr<DeletingLayerAnimationObserver> observer(
        new DeletingLayerAnimationObserver(animator.get()));
    animator->AddObserver(observer.get());

    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(
                target_brightness, brightness_delta)));
    animator->StartAnimation(new LayerAnimationSequence(
        LayerAnimationElement::CreateBoundsElement(
            target_bounds, bounds_delta)));
    ASSERT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));

    animator->set_preemption_strategy(
        LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
    animator->StartAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateBrightnessElement(
                target_brightness, brightness_delta)));

    // Starting the second brightness animation should have aborted the initial
    // brightness animation. |observer| should have stopped the bounds animation
    // as a result.
    ASSERT_FALSE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));

    animator->RemoveObserver(observer.get());
}

// Check that setting a property during an animation with a default animator
// cancels the original animation.
TEST(LayerAnimatorTest, SettingPropertyDuringAnAnimation)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    double start_opacity(0.0);
    double target_opacity(1.0);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetOpacityFromAnimation(start_opacity);

    scoped_ptr<LayerAnimationSequence> sequence(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateOpacityElement(target_opacity, delta)));

    animator->StartAnimation(sequence.release());

    animator->SetOpacity(0.5);

    EXPECT_FALSE(animator->is_animating());
    EXPECT_EQ(0.5, animator->GetTargetOpacity());
}

// Tests that the preemption mode IMMEDIATELY_SET_NEW_TARGET, doesn't cause the
// second sequence to be leaked.
TEST(LayerAnimatorTest, ImmediatelySettingNewTargetDoesNotLeak)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));
    animator->set_preemption_strategy(LayerAnimator::IMMEDIATELY_SET_NEW_TARGET);

    gfx::Rect start_bounds(0, 0, 50, 50);
    gfx::Rect middle_bounds(10, 10, 100, 100);
    gfx::Rect target_bounds(5, 5, 5, 5);

    delegate.SetBoundsFromAnimation(start_bounds);

    {
        // start an implicit bounds animation.
        ScopedLayerAnimationSettings settings(animator.get());
        animator->SetBounds(middle_bounds);
    }

    EXPECT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));

    int num_live_instances = 0;
    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
    scoped_ptr<TestLayerAnimationSequence> sequence(
        new TestLayerAnimationSequence(
            LayerAnimationElement::CreateBoundsElement(target_bounds, delta),
            &num_live_instances));

    EXPECT_EQ(1, num_live_instances);

    // This should interrupt the running sequence causing us to immediately set
    // the target value. The sequence should alse be destructed.
    animator->StartAnimation(sequence.release());

    EXPECT_FALSE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));
    EXPECT_EQ(0, num_live_instances);
    CheckApproximatelyEqual(delegate.GetBoundsForAnimation(), target_bounds);
}

// Verifies GetTargetOpacity() works when multiple sequences are scheduled.
TEST(LayerAnimatorTest, GetTargetOpacity)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));
    animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);

    delegate.SetOpacityFromAnimation(0.0);

    {
        ScopedLayerAnimationSettings settings(animator.get());
        animator->SetOpacity(0.5);
        EXPECT_EQ(0.5, animator->GetTargetOpacity());

        // Because the strategy is ENQUEUE_NEW_ANIMATION the target should now be 1.
        animator->SetOpacity(1.0);
        EXPECT_EQ(1.0, animator->GetTargetOpacity());
    }
}

// Verifies GetTargetBrightness() works when multiple sequences are scheduled.
TEST(LayerAnimatorTest, GetTargetBrightness)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));
    animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);

    delegate.SetBrightnessFromAnimation(0.0);

    {
        ScopedLayerAnimationSettings settings(animator.get());
        animator->SetBrightness(0.5);
        EXPECT_EQ(0.5, animator->GetTargetBrightness());

        // Because the strategy is ENQUEUE_NEW_ANIMATION the target should now be 1.
        animator->SetBrightness(1.0);
        EXPECT_EQ(1.0, animator->GetTargetBrightness());
    }
}

// Verifies GetTargetGrayscale() works when multiple sequences are scheduled.
TEST(LayerAnimatorTest, GetTargetGrayscale)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));
    animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);

    delegate.SetGrayscaleFromAnimation(0.0);

    {
        ScopedLayerAnimationSettings settings(animator.get());
        animator->SetGrayscale(0.5);
        EXPECT_EQ(0.5, animator->GetTargetGrayscale());

        // Because the strategy is ENQUEUE_NEW_ANIMATION the target should now be 1.
        animator->SetGrayscale(1.0);
        EXPECT_EQ(1.0, animator->GetTargetGrayscale());
    }
}

// Verifies color property is modified appropriately.
TEST(LayerAnimatorTest, Color)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    SkColor start_color = SkColorSetARGB(64, 20, 40, 60);
    SkColor middle_color = SkColorSetARGB(128, 35, 70, 120);
    SkColor target_color = SkColorSetARGB(192, 40, 80, 140);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);

    delegate.SetColorFromAnimation(start_color);

    animator->ScheduleAnimation(
        new LayerAnimationSequence(
            LayerAnimationElement::CreateColorElement(target_color, delta)));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_EQ(ColorToString(start_color),
        ColorToString(delegate.GetColorForAnimation()));

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(500));

    EXPECT_TRUE(animator->is_animating());
    EXPECT_EQ(ColorToString(middle_color),
        ColorToString(delegate.GetColorForAnimation()));

    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000));

    EXPECT_FALSE(animator->is_animating());
    EXPECT_EQ(ColorToString(target_color),
        ColorToString(delegate.GetColorForAnimation()));
}

// Verifies SchedulePauseForProperties().
TEST(LayerAnimatorTest, SchedulePauseForProperties)
{
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator());
    animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);
    animator->SchedulePauseForProperties(
        base::TimeDelta::FromMilliseconds(100),
        LayerAnimationElement::TRANSFORM | LayerAnimationElement::BOUNDS);
    EXPECT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::TRANSFORM));
    EXPECT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS));
    EXPECT_FALSE(animator->IsAnimatingProperty(LayerAnimationElement::OPACITY));
}

class AnimatorOwner {
public:
    AnimatorOwner()
        : animator_(CreateDefaultTestAnimator())
    {
    }

    LayerAnimator* animator() { return animator_.get(); }

private:
    scoped_refptr<LayerAnimator> animator_;

    DISALLOW_COPY_AND_ASSIGN(AnimatorOwner);
};

class DeletingObserver : public LayerAnimationObserver {
public:
    DeletingObserver(bool* was_deleted)
        : animator_owner_(new AnimatorOwner)
        , delete_on_animation_ended_(false)
        , delete_on_animation_aborted_(false)
        , delete_on_animation_scheduled_(false)
        , was_deleted_(was_deleted)
    {
        animator()->AddObserver(this);
    }

    ~DeletingObserver() override
    {
        animator()->RemoveObserver(this);
        *was_deleted_ = true;
    }

    LayerAnimator* animator() { return animator_owner_->animator(); }

    bool delete_on_animation_ended() const
    {
        return delete_on_animation_ended_;
    }
    void set_delete_on_animation_ended(bool enabled)
    {
        delete_on_animation_ended_ = enabled;
    }

    bool delete_on_animation_aborted() const
    {
        return delete_on_animation_aborted_;
    }
    void set_delete_on_animation_aborted(bool enabled)
    {
        delete_on_animation_aborted_ = enabled;
    }

    bool delete_on_animation_scheduled() const
    {
        return delete_on_animation_scheduled_;
    }
    void set_delete_on_animation_scheduled(bool enabled)
    {
        delete_on_animation_scheduled_ = enabled;
    }

    // LayerAnimationObserver implementation.
    void OnLayerAnimationEnded(LayerAnimationSequence* sequence) override
    {
        if (delete_on_animation_ended_)
            delete this;
    }

    void OnLayerAnimationAborted(LayerAnimationSequence* sequence) override
    {
        if (delete_on_animation_aborted_)
            delete this;
    }

    void OnLayerAnimationScheduled(LayerAnimationSequence* sequence) override
    {
        if (delete_on_animation_scheduled_)
            delete this;
    }

private:
    scoped_ptr<AnimatorOwner> animator_owner_;
    bool delete_on_animation_ended_;
    bool delete_on_animation_aborted_;
    bool delete_on_animation_scheduled_;
    bool* was_deleted_;

    DISALLOW_COPY_AND_ASSIGN(DeletingObserver);
};

TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterFinishingAnimation)
{
    bool observer_was_deleted = false;
    DeletingObserver* observer = new DeletingObserver(&observer_was_deleted);
    observer->set_delete_on_animation_ended(true);
    observer->set_delete_on_animation_aborted(true);
    LayerAnimator* animator = observer->animator();
    TestLayerAnimationDelegate delegate;
    animator->SetDelegate(&delegate);

    delegate.SetBrightnessFromAnimation(0.0f);

    gfx::Rect start_bounds(0, 0, 50, 50);
    gfx::Rect target_bounds(10, 10, 100, 100);

    delegate.SetBoundsFromAnimation(start_bounds);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
    LayerAnimationSequence* brightness_sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateBrightnessElement(1.0f, delta));
    animator->StartAnimation(brightness_sequence);

    delta = base::TimeDelta::FromSeconds(2);
    LayerAnimationSequence* bounds_sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateBoundsElement(target_bounds, delta));
    animator->StartAnimation(bounds_sequence);

    base::TimeTicks start_time = animator->last_step_time();
    animator->Step(start_time + base::TimeDelta::FromMilliseconds(1500));

    EXPECT_TRUE(observer_was_deleted);
}

TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterStoppingAnimating)
{
    bool observer_was_deleted = false;
    DeletingObserver* observer = new DeletingObserver(&observer_was_deleted);
    observer->set_delete_on_animation_ended(true);
    observer->set_delete_on_animation_aborted(true);
    LayerAnimator* animator = observer->animator();
    TestLayerAnimationDelegate delegate;
    animator->SetDelegate(&delegate);

    delegate.SetOpacityFromAnimation(0.0f);

    gfx::Rect start_bounds(0, 0, 50, 50);
    gfx::Rect target_bounds(10, 10, 100, 100);

    delegate.SetBoundsFromAnimation(start_bounds);

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
    LayerAnimationSequence* opacity_sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateOpacityElement(1.0f, delta));
    animator->StartAnimation(opacity_sequence);

    delta = base::TimeDelta::FromSeconds(2);
    LayerAnimationSequence* bounds_sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateBoundsElement(target_bounds, delta));
    animator->StartAnimation(bounds_sequence);

    animator->StopAnimating();

    EXPECT_TRUE(observer_was_deleted);
}

TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterScheduling)
{
    bool observer_was_deleted = false;
    TestLayerAnimationDelegate delegate;
    DeletingObserver* observer = new DeletingObserver(&observer_was_deleted);
    observer->set_delete_on_animation_scheduled(true);
    LayerAnimator* animator = observer->animator();
    animator->SetDelegate(&delegate);

    delegate.SetOpacityFromAnimation(0.0f);

    gfx::Rect start_bounds(0, 0, 50, 50);
    gfx::Rect target_bounds(10, 10, 100, 100);

    delegate.SetBoundsFromAnimation(start_bounds);

    std::vector<LayerAnimationSequence*> to_start;

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
    to_start.push_back(new LayerAnimationSequence(
        LayerAnimationElement::CreateOpacityElement(1.0f, delta)));

    delta = base::TimeDelta::FromSeconds(2);
    to_start.push_back(new LayerAnimationSequence(
        LayerAnimationElement::CreateBoundsElement(target_bounds, delta)));

    animator->ScheduleTogether(to_start);

    EXPECT_TRUE(observer_was_deleted);
}

TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterAborted)
{
    bool observer_was_deleted = false;
    DeletingObserver* observer = new DeletingObserver(&observer_was_deleted);
    TestLayerAnimationDelegate delegate;
    observer->set_delete_on_animation_aborted(true);
    LayerAnimator* animator = observer->animator();
    animator->set_preemption_strategy(
        LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
    animator->SetDelegate(&delegate);

    delegate.SetOpacityFromAnimation(0.0f);

    gfx::Rect start_bounds(0, 0, 50, 50);
    gfx::Rect target_bounds(10, 10, 100, 100);

    delegate.SetBoundsFromAnimation(start_bounds);

    std::vector<LayerAnimationSequence*> to_start;

    base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
    to_start.push_back(new LayerAnimationSequence(
        LayerAnimationElement::CreateOpacityElement(1.0f, delta)));

    delta = base::TimeDelta::FromSeconds(2);
    to_start.push_back(new LayerAnimationSequence(
        LayerAnimationElement::CreateBoundsElement(target_bounds, delta)));

    animator->ScheduleTogether(to_start);

    EXPECT_FALSE(observer_was_deleted);

    animator->StartAnimation(new LayerAnimationSequence(
        LayerAnimationElement::CreateOpacityElement(1.0f, delta)));

    EXPECT_TRUE(observer_was_deleted);
}

TEST(LayerAnimatorTest, TestSetterRespectEnqueueStrategy)
{
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(CreateDefaultTestAnimator(&delegate));

    float start_opacity = 0.0f;
    float target_opacity = 1.0f;
    float magic_opacity = 0.123f;

    delegate.SetOpacityFromAnimation(start_opacity);

    ScopedLayerAnimationSettings settings(animator.get());
    settings.SetPreemptionStrategy(
        LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
    settings.SetTransitionDuration(base::TimeDelta::FromSeconds(1));
    animator->SetOpacity(target_opacity);

    EXPECT_EQ(start_opacity, delegate.GetOpacityForAnimation());

    settings.SetPreemptionStrategy(
        LayerAnimator::ENQUEUE_NEW_ANIMATION);
    settings.SetTransitionDuration(base::TimeDelta());
    animator->SetOpacity(magic_opacity);

    EXPECT_EQ(start_opacity, delegate.GetOpacityForAnimation());
}

TEST(LayerAnimatorTest, TestScopedCounterAnimation)
{
    Layer parent, child;
    parent.Add(&child);

    gfx::Transform parent_begin, parent_end;

    parent_end.Scale3d(2.0, 0.5, 1.0);

    // Parent animates from identity to the end value. The counter animation will
    // start at the end value and animate back to identity.
    gfx::Transform child_begin(parent_end);

    child.SetTransform(child_begin);
    parent.SetTransform(parent_begin);

    EXPECT_FALSE(child.GetAnimator()->is_animating());

    ScopedLayerAnimationSettings settings(parent.GetAnimator());
    settings.SetInverselyAnimatedBaseLayer(&parent);
    settings.AddInverselyAnimatedLayer(&child);

    parent.SetTransform(parent_end);

    EXPECT_TRUE(child.GetAnimator()->is_animating());
    EXPECT_TRUE(child.GetTargetTransform().IsIdentity())
        << child.GetTargetTransform().ToString();
}

class CollectionLayerAnimationDelegate : public TestLayerAnimationDelegate {
public:
    CollectionLayerAnimationDelegate()
        : collection(NULL)
    {
    }
    ~CollectionLayerAnimationDelegate() override { }

    // LayerAnimationDelegate:
    LayerAnimatorCollection* GetLayerAnimatorCollection() override
    {
        return &collection;
    }

private:
    LayerAnimatorCollection collection;
};

TEST(LayerAnimatorTest, LayerAnimatorCollectionTickTime)
{
    Layer layer;
    LayerAnimator* animator = layer.GetAnimator();
    CollectionLayerAnimationDelegate delegate;
    animator->SetDelegate(&delegate);

    LayerAnimatorCollection* collection = delegate.GetLayerAnimatorCollection();
    base::TimeTicks null;
    collection->OnAnimationStep(null);
    EXPECT_TRUE(collection->last_tick_time().is_null());

    // Adding an animator to the collection should update the last tick time.
    collection->StartAnimator(layer.GetAnimator());
    EXPECT_TRUE(collection->HasActiveAnimators());
    EXPECT_FALSE(collection->last_tick_time().is_null());

    collection->StopAnimator(layer.GetAnimator());
    EXPECT_FALSE(collection->HasActiveAnimators());

    animator->SetDelegate(nullptr);
}

TEST(LayerAnimatorTest, AnimatorStartedCorrectly)
{
    Layer layer;
    LayerAnimatorTestController test_controller(layer.GetAnimator());
    LayerAnimator* animator = test_controller.animator();
    ASSERT_FALSE(animator->is_started_);

    TestLayerAnimationDelegate test_delegate;
    animator->SetDelegate(&test_delegate);
    double target_opacity = 1.0;
    base::TimeDelta time_delta = base::TimeDelta::FromSeconds(1);
    animator->ScheduleAnimation(new LayerAnimationSequence(
        LayerAnimationElement::CreateOpacityElement(target_opacity, time_delta)));
    EXPECT_FALSE(animator->is_started_);

    CollectionLayerAnimationDelegate collection_delegate;
    animator->SetDelegate(&collection_delegate);
    animator->UpdateAnimationState();
    EXPECT_TRUE(animator->is_started_);
    animator->SetDelegate(NULL);
}

TEST(LayerAnimatorTest, AnimatorRemovedFromCollectionWhenLayerIsDestroyed)
{
    scoped_ptr<Layer> layer(new Layer(LAYER_TEXTURED));
    LayerAnimatorTestController test_controller(layer->GetAnimator());
    scoped_refptr<LayerAnimator> animator = test_controller.animator();
    CollectionLayerAnimationDelegate collection_delegate;
    animator->SetDelegate(&collection_delegate);

    double target_opacity = 1.0;
    base::TimeDelta time_delta = base::TimeDelta::FromSeconds(1);
    animator->ScheduleAnimation(new LayerAnimationSequence(
        LayerAnimationElement::CreateOpacityElement(target_opacity, time_delta)));

    EXPECT_TRUE(
        collection_delegate.GetLayerAnimatorCollection()->HasActiveAnimators());

    layer.reset();
    EXPECT_EQ(NULL, animator->delegate());
    EXPECT_FALSE(
        collection_delegate.GetLayerAnimatorCollection()->HasActiveAnimators());
}

TEST(LayerAnimatorTest, LayerMovedBetweenCompositorsDuringAnimation)
{
    bool enable_pixel_output = false;
    ui::ContextFactory* context_factory = InitializeContextFactoryForTests(enable_pixel_output);
    const gfx::Rect bounds(10, 10, 100, 100);
    scoped_ptr<TestCompositorHost> host_1(
        TestCompositorHost::Create(bounds, context_factory));
    scoped_ptr<TestCompositorHost> host_2(
        TestCompositorHost::Create(bounds, context_factory));
    host_1->Show();
    host_2->Show();

    Compositor* compositor_1 = host_1->GetCompositor();
    Layer root_1;
    compositor_1->SetRootLayer(&root_1);

    Compositor* compositor_2 = host_2->GetCompositor();
    Layer root_2;
    compositor_2->SetRootLayer(&root_2);

    // Verify that neither compositor has active animators.
    EXPECT_FALSE(compositor_1->layer_animator_collection()->HasActiveAnimators());
    EXPECT_FALSE(compositor_2->layer_animator_collection()->HasActiveAnimators());

    Layer layer;
    root_1.Add(&layer);
    LayerAnimator* animator = layer.GetAnimator();
    double target_opacity = 1.0;
    base::TimeDelta time_delta = base::TimeDelta::FromSeconds(1);
    animator->ScheduleAnimation(new LayerAnimationSequence(
        LayerAnimationElement::CreateOpacityElement(target_opacity, time_delta)));
    EXPECT_TRUE(compositor_1->layer_animator_collection()->HasActiveAnimators());
    EXPECT_FALSE(compositor_2->layer_animator_collection()->HasActiveAnimators());

    root_2.Add(&layer);
    EXPECT_FALSE(compositor_1->layer_animator_collection()->HasActiveAnimators());
    EXPECT_TRUE(compositor_2->layer_animator_collection()->HasActiveAnimators());
    host_2.reset();
    host_1.reset();
    TerminateContextFactoryForTests();
}

class LayerOwnerAnimationObserver : public LayerAnimationObserver {
public:
    LayerOwnerAnimationObserver(LayerAnimator* animator)
        : animator_layer_(new Layer(LAYER_TEXTURED))
    {
        animator_layer_->SetAnimator(animator);
    }

    ~LayerOwnerAnimationObserver() override { }

    void OnLayerAnimationEnded(LayerAnimationSequence* sequence) override
    {
        ASSERT_TRUE(sequence);
        animator_layer_.reset();
    }

    void OnLayerAnimationAborted(LayerAnimationSequence* sequence) override
    {
        ASSERT_TRUE(sequence);
        animator_layer_.reset();
    }

    LayerAnimationDelegate* animator_layer()
    {
        return animator_layer_.get();
    }

    void OnLayerAnimationScheduled(LayerAnimationSequence* sequence) override { }

private:
    scoped_ptr<Layer> animator_layer_;

    DISALLOW_COPY_AND_ASSIGN(LayerOwnerAnimationObserver);
};

TEST(LayerAnimatorTest, ObserverDeletesLayerInStopAnimating)
{
    scoped_refptr<LayerAnimator> animator(CreateImplicitTestAnimator());
    LayerOwnerAnimationObserver observer(animator.get());
    LayerAnimationDelegate* delegate = observer.animator_layer();

    const gfx::Rect start_bounds(0, 0, 50, 50);
    const gfx::Rect target_bounds(10, 10, 100, 100);
    const double target_opacity = 1.0;

    delegate->SetOpacityFromAnimation(0.0f);
    delegate->SetBoundsFromAnimation(start_bounds);

    base::TimeDelta time_delta = base::TimeDelta::FromSeconds(1);
    LayerAnimationSequence* opacity = new LayerAnimationSequence(
        LayerAnimationElement::CreateOpacityElement(target_opacity, time_delta));
    opacity->AddObserver(&observer);
    animator->ScheduleAnimation(opacity);
    time_delta = base::TimeDelta::FromSeconds(2);
    LayerAnimationSequence* move = new LayerAnimationSequence(
        LayerAnimationElement::CreateBoundsElement(target_bounds, time_delta));
    animator->ScheduleAnimation(move);
    EXPECT_TRUE(animator->is_animating());
    animator->Step(animator->last_step_time() + base::TimeDelta::FromMilliseconds(500));
    animator->StopAnimating();

    EXPECT_EQ(nullptr, observer.animator_layer());
    EXPECT_TRUE(animator->is_animating());
}

// Verifies the LayerAnimatorObserver notification order for an animation
// sequence that completes successfully.
TEST(LayerAnimatorObserverNotificationOrderTest,
    SuccessfulCompletionOfSequence)
{
    TestLayerAnimationObserver observer;
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(
        CreateDefaultTestAnimator(&delegate, &observer));
    observer.set_requires_notification_when_animator_destroyed(true);

    const base::TimeDelta animation_duration = base::TimeDelta::FromSeconds(100);

    LayerAnimationSequence* sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateBrightnessElement(1.0f, animation_duration));

    EXPECT_TRUE(observer.NoEventsObserved());

    animator->StartAnimation(sequence);

    EXPECT_EQ(observer.last_attached_sequence(), sequence);
    EXPECT_EQ(observer.last_scheduled_sequence(), sequence);
    EXPECT_EQ(observer.last_started_sequence(), sequence);
    EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
    EXPECT_EQ(observer.last_ended_sequence(), nullptr);
    EXPECT_EQ(observer.last_detached_sequence(), nullptr);

    EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());
    EXPECT_TRUE(observer.ScheduledEpochIsBeforeStartedEpoch());

    observer.ResetLayerAnimationObserverations();

    const base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + animation_duration);

    EXPECT_EQ(observer.last_attached_sequence(), nullptr);
    EXPECT_EQ(observer.last_scheduled_sequence(), nullptr);
    EXPECT_EQ(observer.last_started_sequence(), nullptr);
    EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
    EXPECT_EQ(observer.last_ended_sequence(), sequence);
    EXPECT_EQ(observer.last_detached_sequence(), sequence);

    EXPECT_TRUE(observer.EndedEpochIsBeforeDetachedEpoch());
}

// Verifies the LayerAnimatorObserver notification order for an animation
// sequence that is aborted after being scheduled.
TEST(LayerAnimatorObserverNotificationOrderTest, AbortingAScheduledSequence)
{
    TestLayerAnimationObserver observer;
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(
        CreateDefaultTestAnimator(&delegate, &observer));
    observer.set_requires_notification_when_animator_destroyed(true);

    const base::TimeDelta animation_duration = base::TimeDelta::FromSeconds(100);

    LayerAnimationSequence* sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateBrightnessElement(1.0f, animation_duration));

    EXPECT_TRUE(observer.NoEventsObserved());

    animator->StartAnimation(sequence);

    EXPECT_EQ(observer.last_attached_sequence(), sequence);
    EXPECT_EQ(observer.last_scheduled_sequence(), sequence);
    EXPECT_EQ(observer.last_started_sequence(), sequence);
    EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
    EXPECT_EQ(observer.last_ended_sequence(), nullptr);
    EXPECT_EQ(observer.last_detached_sequence(), nullptr);

    EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());
    EXPECT_TRUE(observer.ScheduledEpochIsBeforeStartedEpoch());

    observer.ResetLayerAnimationObserverations();

    animator->AbortAllAnimations();

    EXPECT_EQ(observer.last_attached_sequence(), nullptr);
    EXPECT_EQ(observer.last_scheduled_sequence(), nullptr);
    EXPECT_EQ(observer.last_started_sequence(), nullptr);
    EXPECT_EQ(observer.last_aborted_sequence(), sequence);
    EXPECT_EQ(observer.last_ended_sequence(), nullptr);
    EXPECT_EQ(observer.last_detached_sequence(), sequence);

    EXPECT_TRUE(observer.AbortedEpochIsBeforeDetachedEpoch());
}

// Verifies the LayerAnimatorObserver notification order for an animation
// sequence that is queued up after another sequence that
// completes successfully.
TEST(LayerAnimatorObserverNotificationOrderTest,
    RunningASequenceThatIsQueuedForLaterStartTime)
{
    TestLayerAnimationObserver observer;
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(
        CreateDefaultTestAnimator(&delegate, &observer));
    observer.set_requires_notification_when_animator_destroyed(true);

    const base::TimeDelta animation_duration = base::TimeDelta::FromSeconds(100);

    LayerAnimationSequence* first_sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateBrightnessElement(1.0f, animation_duration));

    LayerAnimationSequence* queued_sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateBrightnessElement(1.0f, animation_duration));

    EXPECT_TRUE(observer.NoEventsObserved());

    animator->StartAnimation(first_sequence);

    EXPECT_EQ(observer.last_attached_sequence(), first_sequence);
    EXPECT_EQ(observer.last_scheduled_sequence(), first_sequence);
    EXPECT_EQ(observer.last_started_sequence(), first_sequence);
    EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
    EXPECT_EQ(observer.last_ended_sequence(), nullptr);
    EXPECT_EQ(observer.last_detached_sequence(), nullptr);

    EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());
    EXPECT_TRUE(observer.ScheduledEpochIsBeforeStartedEpoch());

    observer.ResetLayerAnimationObserverations();

    animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);
    animator->StartAnimation(queued_sequence);

    EXPECT_EQ(observer.last_attached_sequence(), queued_sequence);
    EXPECT_EQ(observer.last_scheduled_sequence(), queued_sequence);
    EXPECT_EQ(observer.last_started_sequence(), nullptr);
    EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
    EXPECT_EQ(observer.last_ended_sequence(), nullptr);
    EXPECT_EQ(observer.last_detached_sequence(), nullptr);

    EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());

    observer.ResetLayerAnimationObserverations();

    base::TimeTicks start_time = animator->last_step_time();

    animator->Step(start_time + animation_duration);

    EXPECT_EQ(observer.last_attached_sequence(), nullptr);
    EXPECT_EQ(observer.last_scheduled_sequence(), nullptr);
    EXPECT_EQ(observer.last_started_sequence(), queued_sequence);
    EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
    EXPECT_EQ(observer.last_ended_sequence(), first_sequence);
    EXPECT_EQ(observer.last_detached_sequence(), first_sequence);

    EXPECT_TRUE(observer.EndedEpochIsBeforeDetachedEpoch());
    EXPECT_TRUE(observer.EndedEpochIsBeforeStartedEpoch());
}

// Verifies the LayerAnimatorObserver notification order for an animation
// sequence that pre-empts another sequence.
TEST(LayerAnimatorObserverNotificationOrderTest,
    RunningASequenceThatPreEmptsAnotherSequence)
{
    TestLayerAnimationObserver observer;
    TestLayerAnimationDelegate delegate;
    scoped_refptr<LayerAnimator> animator(
        CreateDefaultTestAnimator(&delegate, &observer));
    observer.set_requires_notification_when_animator_destroyed(true);

    const base::TimeDelta animation_duration = base::TimeDelta::FromSeconds(100);

    LayerAnimationSequence* first_sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateBrightnessElement(1.0f, animation_duration));

    LayerAnimationSequence* queued_sequence = new LayerAnimationSequence(
        LayerAnimationElement::CreateBrightnessElement(1.0f, animation_duration));

    EXPECT_TRUE(observer.NoEventsObserved());

    animator->StartAnimation(first_sequence);

    EXPECT_EQ(observer.last_attached_sequence(), first_sequence);
    EXPECT_EQ(observer.last_scheduled_sequence(), first_sequence);
    EXPECT_EQ(observer.last_started_sequence(), first_sequence);
    EXPECT_EQ(observer.last_aborted_sequence(), nullptr);
    EXPECT_EQ(observer.last_ended_sequence(), nullptr);
    EXPECT_EQ(observer.last_detached_sequence(), nullptr);

    EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());
    EXPECT_TRUE(observer.ScheduledEpochIsBeforeStartedEpoch());

    observer.ResetLayerAnimationObserverations();

    animator->set_preemption_strategy(
        LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
    animator->StartAnimation(queued_sequence);

    EXPECT_EQ(observer.last_attached_sequence(), queued_sequence);
    EXPECT_EQ(observer.last_scheduled_sequence(), queued_sequence);
    EXPECT_EQ(observer.last_started_sequence(), queued_sequence);
    EXPECT_EQ(observer.last_aborted_sequence(), first_sequence);
    EXPECT_EQ(observer.last_ended_sequence(), nullptr);
    EXPECT_EQ(observer.last_detached_sequence(), first_sequence);

    EXPECT_TRUE(observer.AbortedEpochIsBeforeDetachedEpoch());
    EXPECT_TRUE(observer.AbortedEpochIsBeforeStartedEpoch());
    EXPECT_TRUE(observer.AttachedEpochIsBeforeScheduledEpoch());
    EXPECT_TRUE(observer.ScheduledEpochIsBeforeStartedEpoch());
}

} // namespace ui
